﻿using System;
using System.Reflection;
using FluentNHibernate.Conventions;
using FluentNHibernate.Conventions.Instances;
using FluentNHibernate.MappingModel;

namespace NHibernate.Drivers.Azure.TableStorage.Mapping
{
    public class IdShouldBeMappedToRowKeyAndPartitionKeyConvention : IIdConvention
    {
        public void Apply(IIdentityInstance instance)
        {
            instance.Column("RowKey");
            HackPartitionKeyIntoInstance(instance);
            OverwriteIdentifierWith<GuidToPartitionKeyAndRowKey>(instance);
        }

        private static void OverwriteIdentifierWith<T>(IIdentityInstance instance)
        {
            var mapping = GetMapping(instance);
            var typeProperty = mapping.GetType().GetProperty("Type");
            typeProperty.SetValue(mapping, new TypeReference(typeof(T)), null);
        }


        private static void HackPartitionKeyIntoInstance(IIdentityInstance instance)
        {
            var column = Activator.CreateInstance("FluentNHibernate", "FluentNHibernate.MappingModel.ColumnMapping").Unwrap();

            var nameProperty = column.GetType().GetProperty("Name");
            nameProperty.SetValue(column, "PartitionKey", null);

            var mapping = GetMapping(instance);
            var addColumnMethod = mapping.GetType().GetMethod("AddColumn");
            addColumnMethod.Invoke(mapping, new [] {column});

        }

        private static object GetMapping(IIdentityInstance instance)
        {
            var mappingField = instance.GetType().GetField("mapping", BindingFlags.NonPublic | BindingFlags.Instance);
            return mappingField.GetValue(instance);
        }
    }
}